﻿#ifndef _GZIP_H_
#define _GZIP_H_

#include "CommonHead.h"
#include "HashTable.h"
#include "Byte_Info.hpp"
#include "HuffmanTree.hpp"

class GZIP{
public:
	GZIP();
	~GZIP();
	void Compress(const string& filename);
	void DeCompress(const string& filename);
	
private:
	// LZ77
	void BitFlagInfo(u_sh match_len, u_sh match_dist, u_ch& bit_info, u_ch& bit_cnt);
	u_sh LongestMatch(u_sh matchHead, u_sh& matchDist, u_sh start);
	void FillWindow(FILE* file_in, u_ll& read_size, u_sh& start);
	string GetFileName(const string& filename);
	string GetFilePostfix(const string& filename);
	void GetLine(FILE* in, string& str);

	// huffman压缩
	void Hf_Compress();
	void OccurCount();
	void GetCode_Len(hfTree_node<ByteInfo>* root, vector<ByteInfo>& eleminfo, u_ch len);
	void GetCode_Len(hfTree_node<ByteInfo>* root, vector<ByteInfo>& eleminfo);  // 获取编码位长
	void HuffmanCode(vector<ByteInfo>& info);
	void WriteInfo(FILE* file_out);
	void CompressByte(u_sh byte, u_ch& com_byteinfo, u_ch& com_bytecnt);
	void CompressLenDist(u_sh len, u_sh dist, u_ch& compressBitinfo, u_ch& compressBitCnt);
	void WriteCode(size_t code, u_ch code_len, u_ch& com_byteinfo, u_ch& com_bytecnt);
	void Clearinfo();
	u_sh GetLenCode(u_sh match_len);
	u_sh GetDistCode(u_sh match_dist);

	// 解压缩
	void GetCode_leninfo(FILE* file_in);
	void GenerateDecoding(vector<Decoding>& table, vector<ByteInfo>& info);
	u_sh DeCompressSymbol(FILE* file_in, vector<ByteInfo>& codeInfo, vector<Decoding>& decTable, u_ch& ch, u_ch& bit_cnt);
	void GetNextBit(FILE* file_in, u_sh& code, u_ch& ch, u_ch& bit_cnt);

private:
	u_ch* _pwin;
	HashTable hash;

	const u_sh  MIN_READ_SIZE = MIN_MATCH + MAX_MATCH + 1;
	const u_sh  MAX_DIST = WSIZE - MIN_READ_SIZE;   // 最远匹配距离

	// 保存LZ77压缩结果
	vector<u_ch> lz_leninfo;
	vector<u_sh> lz_distinfo;
	vector<u_sh> lz_flaginfo;
	// haffman按块BUF_SIZE的大小进行压缩
	const u_sh BUF_SIZE = 0x8000;

	// 保存LZ77压缩文件的频次信息（创建哈夫曼树）
	vector<ByteInfo> _leninfo;
	vector<ByteInfo> _distinfo;

	bool _lastBlock = false;  // 标记是否最后一个块
	FILE* file_out = nullptr;
};

#endif